package com.pi.shisan.service.audio;

import com.alibaba.fastjson2.annotation.JSONField;
import com.pi.shisan.service.util.ComponentManager;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

@Slf4j
public class MultiFilePlayer extends AudioPlayer{

    /**
     * 0 - 正常态
     * 1 - 干预态
     */
    private volatile int interruptNotifyState = 0;

    private volatile int destroyNotifyState = 0;

    private final List<RepeatTimesConfig> audioFiles;
    private volatile MixPlayer mixPlayer;
    private int pos = -1;

    public MultiFilePlayer(List<RepeatTimesConfig> audioFiles, AudioEffectComponentsSupplier<ComponentManager.MusicEffectBaseComponent> musicEffectComponentsSupplier) throws Exception {
        super(null, musicEffectComponentsSupplier);
        this.audioFiles = new ArrayList<>(audioFiles);
    }

    @Override
    public void setRepeatTimes(int repeatTimes) {
        throw new RuntimeException("不支持在此处设置重复次数");
    }

    @Override
    public boolean playOrResume() {
        playerStatus.compareAndSet(INTERRUPTED,INIT);
        this.interruptNotifyState = 0;
        while (playerStatus.compareAndSet(INIT,PLAYING)) {
            try {
                MixPlayer mixPlayer = this.mixPlayer;
                if (mixPlayer != null) {
                    RepeatTimesConfig config = audioFiles.get(pos);
                    ComponentManager.MusicEffectBaseComponent musicEffectBaseComponent = this.musicEffectComponentsSupplier.get();
                    if (musicEffectBaseComponent != null && musicEffectBaseComponent.getScrollTextComponent()!=null) {
                        musicEffectBaseComponent.getScrollTextComponent().setText(config.getDes() == null ? "" : config.getDes());
                    }
                    if (!mixPlayer.playOrResume()) {
                        return false;
                    }
                    this.mixPlayer = null;
                }
                pos ++;
                if (pos >= this.audioFiles.size()) {
                    playerStatus.set(DESTROYED);
                    return true;
                }
                RepeatTimesConfig config = audioFiles.get(pos);
                try {
                    mixPlayer = new MixPlayer(config.getFile(), this.musicEffectComponentsSupplier);
                    mixPlayer.setPlayBeforeVolume(playBeforeVolume);
                    mixPlayer.setVolume(config.getVolume());
                    ComponentManager.MusicEffectBaseComponent musicEffectBaseComponent = this.musicEffectComponentsSupplier.get();
                    if (musicEffectBaseComponent != null && musicEffectBaseComponent.getScrollTextComponent()!=null) {
                        musicEffectBaseComponent.getScrollTextComponent().setText(config.getDes() == null ? "" : config.getDes());
                    }
                    this.mixPlayer = mixPlayer;
                } catch (Exception e) {
                    log.error("创建混合音乐播放器失败：{}", config.getFile().getAbsolutePath(),e);
                    continue;
                }
                mixPlayer.setRepeatTimes(config.getRepeatTimes());
                if (mixPlayer.playOrResume()) {
                    this.mixPlayer = null;
                } else {
                    return false;
                }
            } finally {
                playerStatus.compareAndSet(PLAYING,INIT);
                if (destroyNotifyState == 1) {
                    return true;
                }
                if (this.interruptNotifyState == 1) {
                    break;
                }
            }
        }
        while (!releaseStatus.compareAndSet(2,3)) {
            if (releaseStatus.get() == 0 || releaseStatus.get() == 3) {
                break;
            }
            Thread.yield();
        }
        return playerStatus.get() == DESTROYED;
    }

    @Override
    public void interrupt() {
        while (!playerStatus.compareAndSet(INIT, INTERRUPTED)) {
            if (playerStatus.get() == INTERRUPTED
                || playerStatus.get() == DESTROYED) {
                break;
            }
            this.interruptNotifyState = 1;
            MixPlayer mixPlayer = this.mixPlayer;
            mixPlayer.interrupt();
            Thread.yield();
        }
    }

    @Override
    public void destroy() {
        releaseStatus.set(1);
        while (!playerStatus.compareAndSet(INIT, DESTROYED)) {
            if (playerStatus.get() == DESTROYED) {
                break;
            }
            playerStatus.compareAndSet(INTERRUPTED, INIT);
            this.destroyNotifyState = 1;
            MixPlayer mixPlayer = this.mixPlayer;
            mixPlayer.destroy();
            Thread.yield();
        }
        releaseStatus.set(2);
    }

    @Override
    protected void doDestroy() {
        throw new RuntimeException("此方法不应该被调用到");
    }

    @Override
    protected boolean doingPlay() throws Exception {
        throw new RuntimeException("此方法不应该被调用到");
    }

    @Override
    protected void reset() throws Exception {
        throw new RuntimeException("此方法不应该被调用到");
    }

    @Override
    public void setPlayBeforeVolume(Consumer<Integer> playBeforeVolume) {
        super.setPlayBeforeVolume(playBeforeVolume);
        final MixPlayer mixPlayer = this.mixPlayer;
        if (mixPlayer != null) {
            mixPlayer.setPlayBeforeVolume(playBeforeVolume);
        }
    }

    @Override
    public void setVolume(Integer volume) {
        //这里禁止设定音量，音量在初始化时已指定
    }

    /**
     * 获取当前正在播放的文件
     * @return
     */
    public RepeatTimesConfig getCurrentPlayFile() {
        if (playerStatus.get() != DESTROYED) {
            int pos = this.pos;
            if (pos < 0) {
                pos = 0;
            }
            return pos >= audioFiles.size() ? null : audioFiles.get(pos);
        }
        return null;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class RepeatTimesConfig{
        @JSONField(write = false)
        private volatile File file;
        private Integer repeatTimes;
        private String des;
        private Integer volume;
    }
}
